using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Drawing;
using EARTHLib;
using ProjectCommon;
namespace ThirdPartyLibraries
{
    public struct CurrentPosition
    {
        public double Altitude;
        public double Latitude;
        public double Longitude;
        public string AltitudeMode;
        public double Range;
        public double Tilt;
    }
    public partial class GoogleEarthViewPort : UserControl, IDisposable
    {
        #region WIN API
        public delegate int EnumWindowsProc(IntPtr hwnd, int lParam);
        [DllImport("user32", CharSet = CharSet.Auto)]
        public extern static IntPtr GetParent(IntPtr hWnd);

        [DllImport("user32", CharSet = CharSet.Auto)]
        public extern static bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

        [DllImport("user32", CharSet = CharSet.Auto)]
        public extern static IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("User32.Dll")]
        public static extern IntPtr PostMessage(IntPtr hWnd, int msg, int wParam, int lParam);

        private const int WM_CLOSE = 0x10;
        #endregion WIN API
        #region VARIABLES
        protected bool _CloseGE = false;
        protected double _ZoomLevel = 10000000;
        public double ZoomLevel
        {
            get { return _ZoomLevel; }
            set { _ZoomLevel = value; }
        }
        public GoogleEarthViewPort()
        {
            InitializeComponent();
        }

        private static IntPtr GEHrender = (IntPtr)0;
        private static IntPtr GEParentHrender = (IntPtr)0;
        private static IntPtr GEMainHrender = (IntPtr)0;
        public ApplicationGEClass m_GoogleEarth;
        private static Point m_ClickedMousePosition;
        private static Point m_ScreenOrigin;

        #endregion VARIABLES
        #region GOOGLE EARTH API FUNCTION CALLS
        private void GoogleEarthViewPort_Load(object sender, EventArgs e)
        {
            if (this.DesignMode == false)
            {
                if(StartGoogleApplication())
                    Start();
            }
        }
        /// <summary>
        /// START GOOGLE EARTH APPLICATION.
        /// IF APPLICATION WAS STARTED CORRECTLY, THEN RETURS TRUE
        /// IF APPLICATION WAS NOT STARTED (I.E. NOT INSTALLED), RETURNS FALSE
        /// </summary>
        /// <returns></returns>
        public bool StartGoogleApplication()
        {
            try
            {
                Timer_Google_Checker.Enabled = true;
                m_GoogleEarth = new ApplicationGEClass();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        public void Start()
        {
            try
            {
                //m_GoogleEarth.GetMyPlaces().Visibility = 1;
                GEHrender = (IntPtr)m_GoogleEarth.GetRenderHwnd();
                GEParentHrender = GetParent(GEHrender);

                GEMainHrender = (IntPtr)m_GoogleEarth.GetMainHwnd();
                SetParent(GEMainHrender, panel1.Handle);

                MoveWindow(GEHrender, 0, 0, this.Width, this.Height, true);
                SetParent(GEHrender, this.Handle);
            }
            catch (Exception ex)
            {
            }
        }
        public void Unload()
        {
            if (GEParentHrender != (IntPtr)0)
            {
                try
                {
                    _CloseGE = true;
                    m_GoogleEarth.Logout();
                    PostMessage(GEHrender, WM_CLOSE, 0, 0);
                    PostMessage(GEMainHrender, WM_CLOSE, 0, 0);
                }
                catch { }
            }
        }

        private void GoogleEarthViewPort_Resize(object sender, EventArgs e)
        {
            if (GEHrender != (IntPtr)0)
                MoveWindow(GEHrender, 0, 0, this.Width, this.Height, true);
        }
        public void GoogleEarth_Resize(int Width, int Height)
        {
            if (GEHrender != (IntPtr)0)
                MoveWindow(GEHrender, 0, 0, Width, Height, true);
        }

        public void LoadKmlData(string KmlData)
        {
            m_GoogleEarth.LoadKmlData(ref KmlData);
        }
        public void OpenKmlFile(string fileName, int suppressMessages)
        {
            if (m_GoogleEarth == null)
                m_GoogleEarth = new ApplicationGEClass();
            m_GoogleEarth.OpenKmlFile(fileName, suppressMessages);
        }

        public int IsInitialized()
        {
            return m_GoogleEarth.IsInitialized();

        }
        public void SetCameraParams()
        {
            PointOnTerrainGE Point = m_GoogleEarth.GetPointOnTerrainFromScreenCoords(0, 0);
            m_GoogleEarth.SetCameraParams(Point.Latitude, Point.Longitude, Point.Altitude, AltitudeModeGE.RelativeToGroundAltitudeGE, ZoomLevel, 0, 0, 1);

        }
        public void ResetZoom()
        {
            _ZoomLevel = 10000000;
            SetCameraParams();
        }

        public void FlyTo(double Latitude, double Longitude, double Altitude)
        {
            try
            {
                double TempAltitude = Altitude;
                if (Altitude < 7000)
                    TempAltitude = 10000;

                if (m_GoogleEarth == null)
                    m_GoogleEarth = new ApplicationGEClass();
                PointOnTerrainGE Point = m_GoogleEarth.GetPointOnTerrainFromScreenCoords(0, 0);

                m_GoogleEarth.SetCameraParams(Latitude, Longitude, TempAltitude, AltitudeModeGE.RelativeToGroundAltitudeGE, 0, 0, 0, 1);
            }
            catch (Exception)
            {
                return;
            }
        }
        public void HideBalloon()
        {
            m_GoogleEarth.HideDescriptionBalloons();
        }
        public CurrentPosition GetCurrentCameraPosition()
        {
            try
            {
                CurrentPosition _CurrentPosition = new CurrentPosition();
                CameraInfoGE _Camera = m_GoogleEarth.GetCamera(1);
                _CurrentPosition.Altitude = _Camera.FocusPointAltitude;
                _CurrentPosition.Latitude = _Camera.FocusPointLatitude;
                _CurrentPosition.Longitude = _Camera.FocusPointLongitude;
                _CurrentPosition.AltitudeMode = _Camera.FocusPointAltitudeMode.ToString();
                _CurrentPosition.Range = _Camera.Range;
                _CurrentPosition.Tilt = _Camera.Tilt;
                return _CurrentPosition;
            }
            catch (Exception)
            {
                return new CurrentPosition();
            }
        }
        public CurrentPosition GetCurrentCoordinates()
        {
            try
            {
                //Point m_ClickedMousePosition;
                //Point m_ScreenOrigin;
                PointOnTerrainGE _PointOnTerrain;
                Point _PositionClickedInGE = new Point();
                double _PercentageWidth;
                double _PercentageHeight;

                _PositionClickedInGE.X = m_ClickedMousePosition.X - m_ScreenOrigin.X;
                _PercentageWidth =  ((2 * ((double)_PositionClickedInGE.X / (double)this.Width)) - 1);

                
                _PositionClickedInGE.Y = m_ClickedMousePosition.Y - m_ScreenOrigin.Y;
                _PercentageHeight = -1 * ((2 * ((double)_PositionClickedInGE.Y / (double)this.Height)) - 1);
                
                _PointOnTerrain = m_GoogleEarth.GetPointOnTerrainFromScreenCoords(_PercentageWidth, _PercentageHeight);
                
                CurrentPosition _CurrentPosition = new CurrentPosition();
                _CurrentPosition.Altitude = _PointOnTerrain.Altitude;
                _CurrentPosition.Latitude = _PointOnTerrain.Latitude;
                _CurrentPosition.Longitude = _PointOnTerrain.Longitude;
                return _CurrentPosition;
            }
            catch (Exception)
            {
                return new CurrentPosition();
            }
        }
        #endregion GOOGLE EARTH API FUNCTION CALLS
        #region GOOGLE EARTH CLICK HOOK HANDLER
        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            CurrentPosition _PositionClicked = GetCurrentCoordinates();
            CurrentPositionArgs CurrentPositionArg = new CurrentPositionArgs(_PositionClicked);
            //TODO: DESKTOP VERSION 2 --> NOT BEING ENABLED FOR NOW. REENABLE TO GET CURRENT POSITION CLICKED
            //ChangePositionClicked(this, CurrentPositionArg);
            //MessageBox.Show(_PositionClicked.Latitude.ToString() + "   " + _PositionClicked.Longitude.ToString());
        }
        public delegate void PositionClickedHandler(object sender, CurrentPositionArgs _CurrentPositionArgs);
        // event declaration
        public event PositionClickedHandler ChangePositionClicked;
        protected override void WndProc(ref Message m)
        {   
            if (m.Msg == 33)
            {
                base.WndProc(ref m);
                
                Point _PositionTemp;
                
                if (m.HWnd == GEHrender || m.HWnd == GEParentHrender)
                {
                    m_ClickedMousePosition = MousePosition;
                    _PositionTemp = new Point(0, 0);
                    m_ScreenOrigin = this.PointToScreen(_PositionTemp);
                    timer1.Enabled = true;
                }
                return;
            }
            base.WndProc(ref m);
        }
        #endregion GOOGLE EARTH CLICK HOOK HANDLER

        private void Timer_Google_Checker_Tick(object sender, EventArgs e)
        {
            string _ProcessName = "googleearth";
            if (!ProcessHelper.IsRunning(_ProcessName) && !_CloseGE)
            {
                StartGoogleApplication();
                Start();
            }
        }


        #region IDisposable Members

        void IDisposable.Dispose()
        {
            Unload();
        }

        #endregion
    }
    public class CurrentPositionArgs : System.EventArgs
    {
        private CurrentPosition m_CurrentPosition;
        public CurrentPositionArgs(CurrentPosition _CurrentPosition)
        {
            this.m_CurrentPosition = _CurrentPosition;
        }
        public CurrentPosition GetCurrentPosition()
        {
            return m_CurrentPosition;
        }
    } 
}


